<?php
/**	
*	FILENAME: 		/libraries/wildcard.php
*	DESCRIPTION:	This library that uses the PHP Snoopy library to interact with Villanova's Office of the Wildcard website.
*	AUTHOR:			Casey Burkhardt
*	VERSION:		1.0.0
*	LAST MODIFIED:	1/2/2010
**/

require_once($_SERVER['DOCUMENT_ROOT'] . "/config/environment.php");
require_once($_SERVER['DOCUMENT_ROOT'] . "/libraries/Snoopy.class.php");

// Define Constants
global $WILDCARD_AUTH_URL, $WILDCARD_ACCOUNT_URL, $WILDCARD_TRANSACTION_DETAIL_URL, $SKEY_LENGTH, $HEADER_DATA;
$WILDCARD_AUTH_URL = "https://services.jsatech.com/login.php";
$WILDCARD_ACCOUNT_URL = "https://services.jsatech.com/index.php";
$WILDCARD_TRANSACTION_DETAIL_URL = "https://services.jsatech.com/statement.php";
$SKEY_LENGTH = 32;
$HEADER_DATA = getHTTPRequestHeaders();

/**	
*	DESCRIPTION:	Creates a valid Wildcard Office authenticated session and returns an authenticated session key (SKEY) value, or FALSE if the session was not created.
**/
function getWildcardSession($studentID, $password) {
	global $WILDCARD_AUTH_URL, $SKEY_LENGTH, $HEADER_DATA;

	// We start by fetching the Wildcard Office website login form.  It contains a hidden form field value "skey", the session key, that we must obtain.
	// Create a new instance of Snoopy, the page fetching / parsing engine.
	$loginPage = new Snoopy;
	
	// We can set a timeout, in case this thing doesn't work, but the Wildcard server is unreliable, so we'll leave it be for now.
	// TODO: Determine if we need a timeout set here.
	//	$loginPage -> read_timeout = 5;
	
	// We will need to fetch pages using HTTPS, so we must point Snoopy to our instance of cURL.
	// This information is stored in our environment configuration.
	$loginPage -> curl_path = getCurlPath();
	
	// Set up appropriate HTTP header data.
	$loginPage -> rawheaders = $HEADER_DATA;

	// The JSA services site is running some strange altered version of Apache.  If you provide a port in the host header, the server bails on the request.
	// This is Snoopy's default action, so we need to alter that.
	$loginPage -> port = FALSE;
	
	// The we're going to be sending URL parameters over a GET request using HTTPS, so we must set this custom-created Snoopy behavior.
	$loginPage -> escape_shell = FALSE;

	if ($loginPage -> fetch($WILDCARD_AUTH_URL)) {
		$searchQueryStart = "<input type='hidden' name='skey' value='";
		$searchQueryEnd = "'";
		$startIndex = strpos($loginPage -> results, $searchQueryStart) + strlen($searchQueryStart);
			if ($startIndex === FALSE) {
				// The session key could not be found, return FALSE
				return FALSE;
			} else {
				$endIndex = strpos($loginPage -> results, $searchQueryEnd, $startIndex);
				$skey = trim(substr($loginPage -> results, $startIndex, $endIndex - $startIndex));
			}
	} else {
		// Downloading the remote page failed, return FALSE.
		return FALSE;
	}
	
	// Check the validity of the session key.
	// The skey value will always be 32 characters long.
	if (strlen($skey) != $SKEY_LENGTH) {
		return FALSE;
	}

	// Continue by posting the login information to the authentication URL.
	$postData["save"] = "1";
	$postData["skey"] = $skey;
	$postData["cid"] = "29";
	$postData["wason"] = "";
	$postData["loginphrase"] = $studentID;
	$postData["password"] = $password;
	
	if ($loginPage -> submit($WILDCARD_AUTH_URL, $postData)) {
		// Check if the login information was incorrect
		if (strpos($loginPage -> results, "Invalid login or password") !== FALSE) {
			// Login information was incorrect, return FALSE.
			return FALSE;
		}
		// Get the next skey for authentication.
		$searchQueryStart = "?skey=";
		$searchQueryEnd = "&";
		$startIndex = strpos($loginPage -> results, $searchQueryStart) + strlen($searchQueryStart);
			if ($startIndex === FALSE) {
				// The session key could not be found, return FALSE
				return FALSE;
			} else {
				$endIndex = strpos($loginPage -> results, $searchQueryEnd, $startIndex);
				$skey = trim(substr($loginPage -> results, $startIndex, $endIndex - $startIndex));
			}
	} else {
		// Downloading the remote page failed, return FALSE.
		return FALSE;
	}
	
	// Check the validity of the session key.
	// The skey value will always be 32 characters long.
	if (strlen($skey) != $SKEY_LENGTH) {
		return FALSE;
	}
	
	// One final request is necessary to complete the session transaction.
	if ($loginPage -> fetch($WILDCARD_AUTH_URL . "?skey=" . $skey . "&cid=29&fullscreen=1&wason=")) {
		// Get the final skey for authentication.
		$searchQueryStart = "index.php?skey=";
		$searchQueryEnd = "&";
		$startIndex = strpos($loginPage -> results, $searchQueryStart) + strlen($searchQueryStart);
		if ($startIndex === FALSE) {
			// The session key could not be found, return FALSE
			return FALSE;
		} else {
			$endIndex = strpos($loginPage -> results, $searchQueryEnd, $startIndex);
			$skey = trim(substr($loginPage -> results, $startIndex, $endIndex - $startIndex));
			return $skey;
		}
	} else {
		// Downloading the remote page failed, return FALSE.
		return FALSE;
	}
}

/**	
*	DESCRIPTION:	Returns an array of all account names, IDs, and balances for which information is availible.
**/
function getAccountBalances($sessionData) {
	global $WILDCARD_ACCOUNT_URL, $HEADER_DATA;
	
	// We must now fetch the wildcard account page.
	// Set up Snoopy with the required parameters.
	$accountPage = new Snoopy;
	$accountPage -> curl_path = getCurlPath();
	$accountPage -> rawheaders = $HEADER_DATA;
	$accountPage -> port = FALSE;
	$accountPage -> escape_shell = FALSE;

	if ($accountPage -> fetch($WILDCARD_ACCOUNT_URL . "?skey=" . $sessionData . "&cid=29")) {
		// Locate and parse the current balance from the Wildcard Restricted Debit Account
		$searchQueryStart = "<b>Current Balance: ";
		$searchQueryEnd = "</b>";
		$startIndex = strpos($accountPage -> results, $searchQueryStart) + strlen($searchQueryStart);
			if ($startIndex === FALSE) {
				// The current balance could not be found, return FALSE
				return FALSE;
			} else {
				$endIndex = strpos($accountPage -> results, $searchQueryEnd, $startIndex);
				$balance = trim(substr($accountPage -> results, $startIndex, $endIndex - $startIndex));
			}
			
		// Locate and parse the account ID for the Wildcard Restricted Debit Account
		$searchQueryStart = "&cid=29&acctto=";
		$searchQueryEnd = "' >View More</a>";
		$startIndex = strpos($accountPage -> results, $searchQueryStart) + strlen($searchQueryStart);
			if ($startIndex === FALSE) {
				// The account ID could not be found, return FALSE
				return FALSE;
			} else {
				$endIndex = strpos($accountPage -> results, $searchQueryEnd, $startIndex);
				$accountID = trim(substr($accountPage -> results, $startIndex, $endIndex - $startIndex));
			}
	} else {
		// Downloading the remote page failed, return FALSE.
		return FALSE;
	}

	// Populate the account data result.
	$accountData = array(
						 "name" 	=>	"Wildcard Restricted Debit Account",
						 "id"		=>	$accountID,
						 "balance"	=>	$balance
						 );
	return $accountData;
}

/**	
*	DESCRIPTION:	Returns an array of transaction data for a given account.
**/
function getTransactionDetails($sessionData, $accountID) {
	global $WILDCARD_TRANSACTION_DETAIL_URL, $HEADER_DATA;
	
	// We must now fetch the wildcard transaction page.
	// Set up Snoopy with the required parameters.
	$transactionPage = new Snoopy;
	$transactionPage -> curl_path = getCurlPath();
	$transactionPage -> rawheaders = $HEADER_DATA;
	$transactionPage -> port = FALSE;
	$transactionPage -> escape_shell = FALSE;
	
	// We'll be posting a request to the form on this page to obtain data for the last six months, the maximum allowable account detail period.
	$postData["save"] = "1";
	$postData["skey"] = $sessionData;
	$postData["cid"] = "29";
	$postData["acctto"] = $accountID;
	$postData["month"] = "13";	

	if ($transactionPage -> submittext($WILDCARD_TRANSACTION_DETAIL_URL . "?skey=" . $sessionData . "&cid=29", $postData)) {
		$searchQueryStart = "Balance";
		$searchQueryEnd = "Ending Balance:";
		// The keywork we're looking for appears twice on this page.  We want the data block to begin after the second occurence.
		$first = strpos($transactionPage -> results, $searchQueryStart) + strlen($searchQueryStart);
		$startIndex = strpos($transactionPage -> results, $searchQueryStart, $first) + strlen($searchQueryStart);
			if ($startIndex === FALSE) {
				// The data block of transactions could not be found, return FALSE
				return FALSE;
			} else {
				$endIndex = strpos($transactionPage -> results, $searchQueryEnd, $startIndex);
				$dataBlock = trim(substr($transactionPage -> results, $startIndex, $endIndex - $startIndex));
			}
	} else {
		// Downloading the remote page failed, return FALSE.
		return FALSE;
	}

	// Delimit the string of transaction data by the line seperator, and place it in an array.
	$transactionData = array();
	$transactionData = explode("\r", $dataBlock);
	
	// Verify the resulting data array
	// We know there are 4 pieces of information for each transaction record, so the size of the array should be a multiple of 4.
	if ((count($tranactionData) % 4) != 0) {
		return FALSE;
	} else {
		// Populate a 2D formatted array with the data
		$formattedData = array();
		$curPos = 0;
		while ($curPos < count($transactionData)) {
			$thisResult = array(
								"date"		=> $transactionData[$curPos],
								"location"	=> $transactionData[$curPos + 1],
								"amount"	=> $transactionData[$curPos + 2],
								"balance"	=> $transactionData[$curPos + 3]
								);
			$formattedData[] = $thisResult;
			$curPos = $curPos + 4;
		}
	}
	return $formattedData;
}
?>